﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.ComponentModel.DataAnnotations;
using Webbness.Mvc.Models;
using Webbness.Mvc.SubSonic;

namespace Webbness.Mvc.Extensions
{
    public static class MVCHelpers
    {
        public static string Feedback(this HtmlHelper helper, Feedback feed)
        {
            if (feed == null)
                return String.Empty;

            var errors = new StringBuilder();
            if (!feed.Successfull)
            {
                foreach (string s in feed.Errors)
                {
                    errors.AppendLine();
                    errors.AppendLine("<div class=\"ui-state-error ui-corner-all\">");
                    errors.AppendLine(
                        "<div class=\"ui-icon ui-icon-alert\" style=\"float: left; margin-right: 0.3em;\"></div>");
                    errors.AppendLine("<p>");
                    errors.Append(s);
                    errors.AppendLine("</p>");
                    errors.AppendLine("</div>");
                }
            }
            else if (!String.IsNullOrEmpty(feed.SuccessMessage))
            {
                errors.AppendLine();
                errors.AppendLine("<div class=\"ui-state-success ui-corner-all\">");
                errors.AppendLine("<p>");
                errors.Append(feed.SuccessMessage);
                errors.AppendLine("</p></div>");
            }

            return errors.ToString();
        }

        public static string Explode(this HtmlHelper helper, object obj)
        {
            return obj.ToString();
        }


        public static string Table(this HtmlHelper helper, object model)
        {
            var enumerable = model as IEnumerable;

            if (enumerable == null)
                return String.Empty;

            Type type = null;

            foreach (var item in enumerable)
            {
                type = item.GetType();
                break;
            }

            if (type == null)
                return "The list is empty";

            var sb = new StringBuilder();
            sb.Append("<table>");
            sb.Append("<tr>");

            PropertyInfo keyprop = null;

            sb.Append("<th>Action</th>");

            foreach (PropertyInfo prop in type.GetProperties())
            {
                if (getDisplayAttribute(prop))
                {
                    sb.AppendFormat("<th>{0}</th>", getLabelText(prop));
                }
                if (CheckForKey(type.Name, prop))
                {
                    keyprop = prop;
                }
            }

            if (keyprop == null)
                throw new NullReferenceException("No Id Property found.");

            sb.Append("</tr>");

            foreach (object obj in enumerable)
            {
                sb.Append("<tr>");

                object keyvalue = keyprop.GetValue(obj, null);

                sb.Append("<th>");
                sb.Append(helper.ActionLink("Display", "Display", new {id = keyvalue}));
                if (helper.ViewContext.HttpContext.User.IsInRole("admin"))
                    sb.AppendFormat("&nbsp;{0}&nbsp;{1}", helper.ActionLink("Edit", "Edit", new {id = keyvalue}), helper.ActionLink("Delete", "Delete", new {id = keyvalue}));
                sb.Append("</th>");

                foreach (PropertyInfo prop in type.GetProperties())
                {
                    if (getDisplayAttribute(prop))
                    {
                        object propValue = prop.GetValue(obj, null);
                        sb.AppendFormat("<td>{0}</td>", formatPropVal(propValue));
                    }
                }
                sb.Append("</tr>");
            }
            sb.Append("</table>");
            return sb.ToString();
        }

        private static bool CheckForKey(string typeName, PropertyInfo prop)
        {
            foreach (var att in prop.GetCustomAttributes(true))
            {
                if (att.ToString().Equals("SubSonic.SqlGeneration.Schema.SubSonicPrimaryKeyAttribute"))
                {
                    return true;
                }
            }

            return prop.Name.Equals(typeName + "ID", StringComparison.InvariantCultureIgnoreCase) || prop.Name.Equals("ID", StringComparison.InvariantCultureIgnoreCase);
        }

        private static string formatPropVal(object value)
        {
            if (value == null)
                return String.Empty;

            if (value is String)
                return value.ToString();
            if (value is DateTime)
                return ((DateTime) value).ToShortDateString();

            return value.ToString();
        }

        private static string getLabelText(PropertyInfo prop)
        {
            var atts = prop.GetCustomAttributes(typeof(DisplayNameAttribute), true);
            if (atts.Length == 0)
                return prop.Name;
            var att = (DisplayNameAttribute)atts[0];
            return att.DisplayName;
        }

        private static bool getDisplayAttribute(PropertyInfo prop)
        {
            var atts = prop.GetCustomAttributes(typeof(ScaffoldInListAttribute), true);
            if (atts.Length == 0)
                return true;
            var att = (ScaffoldInListAttribute)atts[0];
            return att.Scaffold;
        }

        public static List<SelectListItem> SelectFromList<T>(this HtmlHelper helper, Expression<Func<T, bool>> expression) where T : Record, new()
        {
            Record record = (Record)helper.ViewData.Model;
            var lst = new List<SelectListItem>();
            try
            {
                foreach (T item in Repository.Repo.Find<T>(expression))
                {
                    var s = new SelectListItem();
                    s.Text = item.ToString();
                    s.Value = item.Id.ToString();
                    s.Selected = item.Id.Equals(record.Id);
                    lst.Add(s);
                }
            }
            catch(Exception ex)
            {
                System.Diagnostics.Trace.TraceError(ex.Message);
            }
            return lst;
        }
    }
}